package com.yonyou.sto.modules.ums.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yonyou.sto.common.exception.Asserts;
import com.yonyou.sto.domain.AdminUserDetails;
import com.yonyou.sto.modules.ims.model.ImsPartyAdminRelation;
import com.yonyou.sto.modules.ims.service.ImsPartyAdminRelationService;
import com.yonyou.sto.modules.ums.dto.SelectCheckerParam;
import com.yonyou.sto.modules.ums.dto.UmsAdminParam;
import com.yonyou.sto.modules.ums.dto.UpdateAdminPasswordParam;
import com.yonyou.sto.modules.ums.mapper.UmsAdminLoginLogMapper;
import com.yonyou.sto.modules.ums.mapper.UmsAdminMapper;
import com.yonyou.sto.modules.ums.mapper.UmsResourceMapper;
import com.yonyou.sto.modules.ums.mapper.UmsRoleMapper;
import com.yonyou.sto.modules.ums.model.*;
import com.yonyou.sto.modules.ums.service.UmsAdminCacheService;
import com.yonyou.sto.modules.ums.service.UmsAdminOrgRelationService;
import com.yonyou.sto.modules.ums.service.UmsAdminRoleRelationService;
import com.yonyou.sto.modules.ums.service.UmsAdminService;
import com.yonyou.sto.security.util.JwtTokenUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * 后台管理员管理Service实现类
 * Created by aegon on 2018/4/26.
 */
@Service
public class UmsAdminServiceImpl extends ServiceImpl<UmsAdminMapper, UmsAdmin> implements UmsAdminService {
    private static final Logger LOGGER = LoggerFactory.getLogger(UmsAdminServiceImpl.class);
    @Resource
    private UmsAdminMapper umsAdminMapper;
    @Resource
    private JwtTokenUtil jwtTokenUtil;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private UmsAdminLoginLogMapper loginLogMapper;
    @Resource
    private UmsAdminCacheService adminCacheService;
    @Resource
    private UmsAdminRoleRelationService adminRoleRelationService;
    @Resource
    private ImsPartyAdminRelationService imsPartyAdminRelationService;
    @Resource
    private UmsRoleMapper roleMapper;
    @Resource
    private UmsResourceMapper resourceMapper;
    @Resource
    private UmsAdminOrgRelationService umsAdminOrgRelationService;

    @Override
    public UmsAdmin getAdminByUsername(String username) {
        //UmsAdmin admin = adminCacheService.getAdmin(username);
        //if(admin!=null) return  admin;
        QueryWrapper<UmsAdmin> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UmsAdmin::getUsername,username);
        List<UmsAdmin> adminList = list(wrapper);
        if (adminList != null && adminList.size() > 0) {
            UmsAdmin admin = adminList.get(0);
            //adminCacheService.setAdmin(admin);
            return admin;
        }
        return null;
    }

    @Override
    public UmsAdmin getAdminById(String id) {
        return umsAdminMapper.selectById(id);
    }


    @Override
    public String register(UmsAdminParam umsAdminParam) {
        UmsAdmin umsAdmin = new UmsAdmin();
        BeanUtils.copyProperties(umsAdminParam, umsAdmin);
        //if ((!umsAdminParam.getNc_ID().isEmpty())&&umsAdmin.getNc_ID().isEmpty()) {
        //    umsAdmin.setNc_ID(umsAdminParam.getNc_ID());
        //}
        umsAdmin.setCreateTime(new Date());
        umsAdmin.setStatus(1);
        //查询是否有相同用户名的用户
        QueryWrapper<UmsAdmin> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UmsAdmin::getUsername,umsAdmin.getUsername());
        List<UmsAdmin> umsAdminList = list(wrapper);
        if (umsAdminList.size() > 0) {
            return "用户名重复";
        }
        //将密码进行加密操作
        String encodePassword = passwordEncoder.encode(umsAdmin.getPassword());
        umsAdmin.setPassword(encodePassword);
        baseMapper.insert(umsAdmin);

        // 设置角色关联
        updateRole(umsAdmin.getId(), umsAdminParam.getRole());
        // 设置组织关联
        //updateParty(umsAdmin.getId(), umsAdminParam.getParty());
        updateParty(umsAdmin.getId(),umsAdminParam.getParty());

        return "success";
    }

    @Override
    public String login(String username, String password) {
        String token = null;
        //密码需要客户端加密后传递
        try {
            UserDetails userDetails = loadUserByUsername(username);
            if(!passwordEncoder.matches(password,userDetails.getPassword())){
                Asserts.fail("密码不正确");
            }
            if(!userDetails.isEnabled()){
                Asserts.fail("帐号已被禁用");
            }
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            token = jwtTokenUtil.generateToken(userDetails);
//            updateLoginTimeByUsername(username);
            insertLoginLog(username);
        } catch (AuthenticationException e) {
            LOGGER.warn("登录异常:{}", e.getMessage());
        }
        return token;
    }

    /**
     * 添加登录记录
     * @param username 用户名
     */
    private void insertLoginLog(String username) {
        UmsAdmin admin = getAdminByUsername(username);
        if(admin==null) return;
        UmsAdminLoginLog loginLog = new UmsAdminLoginLog();
        loginLog.setAdminId(admin.getId());
        loginLog.setCreateTime(new Date());
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        loginLog.setIp(request.getRemoteAddr());
        loginLogMapper.insert(loginLog);
    }

    /**
     * 根据用户名修改登录时间
     */
    private void updateLoginTimeByUsername(String username) {
        UmsAdmin record = new UmsAdmin();
        record.setLoginTime(new Date());
        QueryWrapper<UmsAdmin> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UmsAdmin::getUsername,username);
        update(record,wrapper);
    }

    @Override
    public String refreshToken(String oldToken) {
        return jwtTokenUtil.refreshHeadToken(oldToken);
    }

    @Override
    public Page<UmsAdmin> list(String keyword, Integer pageSize, Integer pageNum) {
        Page<UmsAdmin> page = new Page<>(pageNum,pageSize);
        QueryWrapper<UmsAdmin> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<UmsAdmin> lambda = wrapper.lambda();
        lambda.ne(UmsAdmin::getUsername,"admin");
        lambda.orderByDesc(UmsAdmin::getCreateTime);
        if(StrUtil.isNotEmpty(keyword)){
            lambda.like(UmsAdmin::getUsername,keyword);
            lambda.or().like(UmsAdmin::getNickName,keyword);
        }
        Page<UmsAdmin> page1 = page(page, wrapper);
        if (page1.getRecords().size()>0)
            return page1;
        page.setCurrent(pageNum-1);
        return page(page, wrapper);
    }

    @Override
    public boolean update(String id, UmsAdmin admin) {
        admin.setId(id);
        UmsAdmin rawAdmin = getById(id);
        if(rawAdmin.getPassword().equals(admin.getPassword())){
            //与原加密密码相同的不需要修改
            admin.setPassword(null);
        }else{
            //与原加密密码不同的需要加密修改
            if(StrUtil.isEmpty(admin.getPassword())){
                admin.setPassword(null);
            }else{
                admin.setPassword(passwordEncoder.encode(admin.getPassword()));
                //adminCacheService.delAdmin(admin.getId());
            }
        }
        boolean success = updateById(admin);
        //adminCacheService.delAdmin(id);
        return success;
    }

    @Override
    public boolean delete(String id) {
        //adminCacheService.delAdmin(id);
        boolean success = removeById(id);
        //adminCacheService.delResourceList(id);
        return success;
    }

    @Override
    public int updateRole(String adminId, List<String> roleIds) {
        int count = roleIds == null ? 0 : roleIds.size();
        //先删除原来的关系
        QueryWrapper<UmsAdminRoleRelation> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UmsAdminRoleRelation::getAdminId,adminId);
        adminRoleRelationService.remove(wrapper);
        //建立新关系
        if (!CollectionUtils.isEmpty(roleIds)) {
            List<UmsAdminRoleRelation> list = new ArrayList<>();
            for (String roleId : roleIds) {
                UmsAdminRoleRelation roleRelation = new UmsAdminRoleRelation();
                roleRelation.setAdminId(adminId);
                roleRelation.setRoleId(roleId);
                list.add(roleRelation);
                adminRoleRelationService.save(roleRelation);
            }
            //adminRoleRelationService.saveBatch(list);
        }
        //adminCacheService.delResourceList(adminId);
        return count;
    }

    @Override
    public int updateParty(String adminId, List<String> partyIds){
        int count = partyIds == null ? 0 : partyIds.size();
        //先删除原来的关系
        umsAdminOrgRelationService.remove(new LambdaQueryWrapper<UmsAdminOrgRelation>()
                .eq(UmsAdminOrgRelation::getAdminId,adminId)
        );
        //建立新关系
        if (!CollectionUtils.isEmpty(partyIds)) {
            List<UmsAdminOrgRelation> list = new ArrayList<>();
            for (String partyId : partyIds) {
                UmsAdminOrgRelation umsAdminOrgRelation = new UmsAdminOrgRelation();
                umsAdminOrgRelation.setAdminId(adminId);
                umsAdminOrgRelation.setNcorgId(partyId);
                list.add(umsAdminOrgRelation);
                umsAdminOrgRelationService.save(umsAdminOrgRelation);
            }
            //umsAdminOrgRelationService.saveBatch(list);
        }
        return count;
    }

    //@Override
    public int updateOrg(String adminId, List<String> OrgIds){
        int count = OrgIds == null ? 0 : OrgIds.size();
        //先删除原来的关系
        QueryWrapper<ImsPartyAdminRelation> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(ImsPartyAdminRelation::getAdminId,adminId);
        imsPartyAdminRelationService.remove(wrapper);
        boolean result = umsAdminOrgRelationService.remove(
                new LambdaQueryWrapper<UmsAdminOrgRelation>()
                        .eq(UmsAdminOrgRelation::getAdminId, adminId)
        );
        if (!result){
            return 0;
        }
        //建立新关系
        if(!CollectionUtils.isEmpty(OrgIds)){
            List<UmsAdminOrgRelation> list = new ArrayList<>();
            for (String orgId : OrgIds) {
                UmsAdminOrgRelation umsAdminOrgRelation = new UmsAdminOrgRelation();
                umsAdminOrgRelation.setAdminId(adminId);
                umsAdminOrgRelation.setNcorgId(orgId);
                list.add(umsAdminOrgRelation);
            }
            umsAdminOrgRelationService.saveBatch(list);
        }
        //建立新关系
//        if (!CollectionUtils.isEmpty(partyIds)) {
//            List<ImsPartyAdminRelation> list = new ArrayList<>();
//            for (Long PartyId : partyIds) {
//                ImsPartyAdminRelation PartyRelation = new ImsPartyAdminRelation();
//                PartyRelation.setAdminId(adminId);
//                PartyRelation.setPartyId(PartyId);
//                list.add(PartyRelation);
//            }
//            imsPartyAdminRelationService.saveBatch(list);
//        }
        return count;
    }

    @Override
    public List<UmsRole> getRoleList(String adminId) {
        return roleMapper.getRoleList(adminId);
    }

    @Override
    public List<UmsResource> getResourceList(String adminId) {
        /*List<UmsResource> resourceList = adminCacheService.getResourceList(adminId);
        if(CollUtil.isNotEmpty(resourceList)){
            return  resourceList;
        }*/
        List<UmsResource> resourceList = resourceMapper.getResourceList(adminId);
        if(CollUtil.isNotEmpty(resourceList)){
            adminCacheService.setResourceList(adminId,resourceList);
        }
        return resourceList;
    }

    @Override
    public int updatePassword(UpdateAdminPasswordParam param) {
        if(StrUtil.isEmpty(param.getUsername())
                ||StrUtil.isEmpty(param.getOldPassword())
                ||StrUtil.isEmpty(param.getNewPassword())){
            return -1;
        }
        QueryWrapper<UmsAdmin> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UmsAdmin::getUsername,param.getUsername());
        List<UmsAdmin> adminList = list(wrapper);
        if(CollUtil.isEmpty(adminList)){
            return -2;
        }
        UmsAdmin umsAdmin = adminList.get(0);
        if(!passwordEncoder.matches(param.getOldPassword(),umsAdmin.getPassword())){
            return -3;
        }
        umsAdmin.setPassword(passwordEncoder.encode(param.getNewPassword()));
        updateById(umsAdmin);
        //adminCacheService.delAdmin(umsAdmin.getId());
        return 1;
    }

    @Override
    public UserDetails loadUserByUsername(String username){
        //获取用户信息
        UmsAdmin admin = getAdminByUsername(username);
        if (admin != null) {
            List<UmsResource> resourceList = getResourceList(admin.getId());
            return new AdminUserDetails(admin,resourceList);
        }
        throw new UsernameNotFoundException("用户名或密码错误");
    }


    @Override
    public List<SelectCheckerParam> getSelectChecker() {
        QueryWrapper<UmsAdmin> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UmsAdmin::getStatus, 1);
        List<UmsAdmin> admins = list(wrapper);
        List<SelectCheckerParam> params = new ArrayList<>();
        admins.forEach(umsAdmin -> {
            SelectCheckerParam param = new SelectCheckerParam();
            param.setUsername(umsAdmin.getUsername());
            param.setNickName(umsAdmin.getNickName());
            params.add(param);
        });
        return params;
    }
}
